package com.toKnow.service.impl;

import com.toKnow.mapper.UserInfoMapper;
import com.toKnow.mapper.UtilMapper;
import com.toKnow.model.dto.*;
import com.toKnow.model.dto.transfer.UserEditNormalDTOTransfer;
import com.toKnow.model.dto.transfer.UserInfoDTOTransfer;
import com.toKnow.model.entity.UserInfo;
import com.toKnow.service.ProfileService;
import com.toKnow.service.RegisterService;
import com.toKnow.utils.FormatUtil;
import com.toKnow.utils.JwtActivateUtil;
import com.toKnow.utils.MailUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.Objects;
import java.util.UUID;

@Service
public class ProfileServiceImpl implements ProfileService {

    @Resource
    private UserInfoMapper userInfoMapper;

    @Resource
    private UtilMapper utilMapper;

    //仅仅调用isDuplicate方法
    @Resource
    private RegisterService registerService;

    @Override
    public UserInfoDTO getUserInfo(String fieldName, String fieldValue) {
        UserInfo userInfo = userInfoMapper.selectActiveUserByUniqueAttr(fieldName, fieldValue);
        UserInfoDTO userInfoDTO = null;
        if(userInfo != null){
            String education = utilMapper.selectNameByEducationId(userInfo.getEducationId());
            String university = utilMapper.selectNameByUniversityId(userInfo.getUniversityId());
            userInfoDTO = UserInfoDTOTransfer.INSTANCE.fromUserInfo(userInfo);
            userInfoDTO.setEducation(education);
            userInfoDTO.setUniversity(university);
        }
        return userInfoDTO;
    }

    @Override
    public UserInfoDTO getAuthorInfo(Integer authorId) {
        UserInfo userInfo = userInfoMapper.getAuthorInfo(authorId);
        UserInfoDTO userInfoDTO = null;
        if(userInfo != null){
            String education = utilMapper.selectNameByEducationId(userInfo.getEducationId());
            String university = utilMapper.selectNameByUniversityId(userInfo.getUniversityId());
            userInfoDTO = UserInfoDTOTransfer.INSTANCE.fromUserInfo(userInfo);
            userInfoDTO.setEducation(education);
            userInfoDTO.setUniversity(university);
        }
        return userInfoDTO;
    }

    /**
     * 辅助用户普通信息修改的操作，修改头像（会把之前的文件删除避免占用空间）
     * 成功返回新头像的相对地址，未变则返回null，否则返回""
     */
    private String replaceAvatar(String originalAvatar, HttpServletRequest request, MultipartFile file) {
        if (file != null && !Objects.equals(file.getOriginalFilename(), "")) {
            //获取文件的后缀名 .jpg
            int lastIndexOf = Objects.requireNonNull(file.getOriginalFilename()).lastIndexOf(".");
            String suffix = file.getOriginalFilename().substring(lastIndexOf);
            if (!(suffix.equalsIgnoreCase(".png")
                || suffix.equalsIgnoreCase(".jpg")
                || suffix.equalsIgnoreCase(".jpeg"))) {
                return "";
            }
            //根据时间戳创建新的文件名，这样即便是第二次上传相同名称的文件，也不会把第一次的文件覆盖了
            String fileName = System.currentTimeMillis() + suffix;
            //获取当前项目的真实路径，然后拼接前面的文件
            String destFileName = request.getServletContext().getRealPath("") + "/static/avatar" + File.separator + fileName;
            //第一次运行的时候，这个文件所在的目录往往是不存在的，这里需要创建一下目录（创建到了webapp下static/avatar文件夹下）
            File destFile = new File(destFileName);
            if (!destFile.getParentFile().exists()) {
                if (destFile.getParentFile().mkdirs()) { //新建文件夹失败
                    return "";
                }
            }
            //把浏览器上传的文件复制到希望的位置
            try {
                file.transferTo(destFile);
            } catch (IOException e) {
                return "";
            }
            //删除原来的文件
            if (originalAvatar != null && !originalAvatar.equals("")) {
                File deleteFile = new File(request.getServletContext().getRealPath("") + originalAvatar);
                if (deleteFile.exists() && !deleteFile.delete()) { //删除原文件失败
                    return "";
                }
            }
            //更新用户头像
            return "/static/avatar/" + fileName; // 相对路径
        } else {
            return null;
        }
    }

    @Override
    @Transactional
    public String modifyUserNormal(HttpServletRequest request, Integer id, MultipartFile avatar, UserEditNormalDTO userEditNormalDTO) {
        //获取用户原信息
        UserInfo originalUserInfo = userInfoMapper.selectActiveUserByUniqueAttr("id", id);
        //检查新用户名是否合法
        String newUsername = userEditNormalDTO.getUsername();
        Integer newUsernameId = registerService.isDuplicate("username", newUsername);
        if (newUsernameId > 0 && !newUsernameId.equals(id)) { // 重复
            return "用户名已存在";
        } else {
            String checkUsernameMsg = FormatUtil.checkUsername(newUsername);
            if (!checkUsernameMsg.equals("")) {
                return checkUsernameMsg;
            }
        }
        //检查性别是否合法
        Integer sex = userEditNormalDTO.getSex();
        if (sex != null && !(sex == 0 || sex == 1)) {
            return "没有此性别";
        }
        //检查并获取用户学历和学校
        String education = userEditNormalDTO.getEducation();
        Integer educationId = utilMapper.selectEducationIdByName(education);
        if (education != null && !education.equals("") && educationId == null) {
            return "没有此学历";
        }
        String university = userEditNormalDTO.getUniversity();
        Integer universityId = utilMapper.selectUniversityIdByName(university);
        if (university != null && !university.equals("") && universityId == null) {
            return "没有此大学";
        }
        //更新用户头像
        String originalAvatar = originalUserInfo.getAvatar();
        String newAvatar = replaceAvatar(originalAvatar, request, avatar);
        if (newAvatar != null && newAvatar.equals("")) {
            return "更新用户头像出错，请上传jpg/jpeg/png文件";
        }
        //将DTO转换为ENTITY插入
        UserInfo userInfo = UserEditNormalDTOTransfer.INSTANCE.toUserInfo(userEditNormalDTO);
        userInfo.setId(id);
        userInfo.setEducationId(educationId);
        userInfo.setUniversityId(universityId);
        if (newAvatar == null) { //原头像
            userInfo.setAvatar(originalAvatar);
        } else {
            userInfo.setAvatar(newAvatar);
        }
        int success = userInfoMapper.updateUser(userInfo);
        if (success != 1) {
            return "更新用户信息出错";
        }
        return "";
    }

    /**
     * 辅助用户修改邮箱和密码，修改用户信息中的激活码
     * 成功返回1
     */
    @SuppressWarnings("BooleanMethodIsAlwaysInverted")
    private boolean setActivateCode(Integer id, String activateCode){
        UserInfo userUpdateActivateCode = new UserInfo();
        userUpdateActivateCode.setId(id);
        userUpdateActivateCode.setActivateCode(activateCode);
        return userInfoMapper.updateUser(userUpdateActivateCode) == 1;
    }

    @Override
    @Transactional
    public String tryToModifyUserAccount(HttpServletRequest request, Integer id, String fieldName, String fieldValue){
        //检查fieldName
        if(!(fieldName.equals("email") || fieldName.equals("userpwd"))){
            return "请修改邮箱或密码";
        }
        //获取用户原信息
        UserInfo originalUserInfo = userInfoMapper.selectActiveUserByUniqueAttr("id", id);
        //检查修改的字段是否符合规范
        if(fieldName.equals("email")){
            //检查新邮箱是否合法
            Integer newId = registerService.isDuplicate(fieldName, fieldValue);
            if(newId > 0 && !newId.equals(id)){ //重复
                return "用户邮箱已存在于其他账户";
            }else if(newId > 0){ //未改变
                return "邮箱未改变";
            }else { //不重复
                String checkEmailMsg = FormatUtil.checkEmail(fieldValue);
                if (!checkEmailMsg.equals("")) {
                    return checkEmailMsg;
                }
            }
        }else{
            //检查新密码是否合法
            String checkUserpwdMsg = FormatUtil.checkUserpwd(fieldValue);
            if(!checkUserpwdMsg.equals("")){
                return checkUserpwdMsg;
            }
        }
        //设置激活码
        String activateCode = UUID.randomUUID().toString().replaceAll("-", "");
        if(!setActivateCode(id, activateCode)) {
            return "修改用户信息失败";
        }
        //发送验证邮件
        //收件人
        String to = fieldName.equals("email") ? fieldValue : originalUserInfo.getEmail();
        //邮件内容
        UserRegisterDTO userRegisterDTO = new UserRegisterDTO();
        userRegisterDTO.setUsername(originalUserInfo.getUsername());
        if(fieldName.equals("email")) {
            userRegisterDTO.setUserpwd(originalUserInfo.getUserpwd());
            userRegisterDTO.setEmail(fieldValue);
        }else{
            userRegisterDTO.setUserpwd(fieldValue);
            userRegisterDTO.setEmail(originalUserInfo.getEmail());
        }
        userRegisterDTO.setActivateCode(activateCode);
        String activateToken = JwtActivateUtil.sign(userRegisterDTO);
        String activateHref = request.getScheme() + "://" + request.getServerName() + ":"
                + request.getServerPort() + request.getContextPath() + "/api/"
                + "user/info/edit/" + fieldName + "/confirm?activateToken=" + activateToken;
        String ChineseHint = fieldName.equals("email") ? "绑定邮箱" : "密码";
        String text = "<html><head></head><body><h1>用户" + userRegisterDTO.getUsername()
                + "申请修改" + ChineseHint + "成功！请在15分钟内点击以下链接确认修改</h1>"
                + "<h3><a href='" + activateHref + "' target='_self'>修改" + ChineseHint + "</a></h3></body></html>";
        //邮件标题
        String title = "修改toKnow" + ChineseHint;
        //发送邮件(发件人信息在MailUtil中可以修改)
        boolean sendSuccess = MailUtil.sendMail(to, text, title);
        return sendSuccess ? "" : "邮件发送失败";
    }

    @Override
    @Transactional
    public String modifyUserAccount(String username, String activateCode, String fieldName, String fieldValue) {
        UserInfo userInfo = userInfoMapper.selectActiveUserByUniqueAttr("username", username);
        if(userInfo == null){
            return "不存在该用户";
        }
        String realActivateCode = userInfo.getActivateCode();
        if(realActivateCode == null || !realActivateCode.equals(activateCode)){
            return "激活码错误";
        }
        if(fieldName.equals("email")){
            userInfo.setEmail(fieldValue);
        }else if(fieldName.equals("userpwd")){
            userInfo.setUserpwd(DigestUtils.md5Hex(fieldValue));
        }
        int updateSuccess = userInfoMapper.updateUser(userInfo);
        return updateSuccess == 1 ? "" : "更新失败";
    }

    @Transactional
    public String modifyUserPassword(String username, String userpwd) {
        UserInfo userInfo = userInfoMapper.selectActiveUserByUniqueAttr("username", username);
        if(userInfo == null){
            return "不存在该用户";
        }
        userInfo.setUserpwd(DigestUtils.md5Hex(userpwd));

        int updateSuccess = userInfoMapper.updateUser(userInfo);
        return updateSuccess == 1 ? "" : "更新失败";
    }
}